{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import ipywidgets as widgets\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "from IPython.display import display, clear_output\n",
    "from ipywidgets import (interact, interactive, fixed, Layout, interact_manual,\n",
    "                       IntText, FloatText, IntSlider, BoundedIntText, FloatSlider,\n",
    "                        BoundedFloatText, Box, HBox, VBox,\n",
    "                        Tab, Accordion, ToggleButton,  Dropdown)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Interact"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(name, x):\n",
    "    print(name, x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "90f2823f9b724802a40d6b5e551c758f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(IntSlider(value=10, description='X', max=30, min=-10), Output()), _dom_classes=('widget-…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "fe9b81f06c7a43aca994e4a7392655c7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(FloatText(value=10.0, description='x', step=1.0), Output()), _dom_classes=('widget-inter…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b546c3e425224b15b6321682601cc0d4",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(Text(value='Hello', description='x'), Output()), _dom_classes=('widget-interact',))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "interact(f, name=fixed('xx'), x=widgets.IntSlider(min=-10, max=30, step=1, value=10, description='X'));\n",
    "interact(f, name=fixed('yy'), x=widgets.FloatText(min=-10, max=30, step=1, value=10));\n",
    "interact(f, name=fixed('zz'), x=widgets.Text('Hello'));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e5989563d7f1428abec993a4814b1d1b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(FloatSlider(value=1.0, description='i', max=7.0, min=1.0, step=1.0), Button(description=…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "273e8592466f49f9a8008b2d5851b883",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(IntSlider(value=1, description='i', max=7, min=1), Button(description='Run Interact', st…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def slow_function(i):\n",
    "    print(int(i),list(x for x in range(int(i)) if\n",
    "                str(x)==str(x)[::-1] and\n",
    "                str(x**2)==str(x**2)[::-1]))\n",
    "    return\n",
    "interact_manual(slow_function,i=FloatSlider(min=1.0, max=7.0, step=1.0));\n",
    "interact_manual(slow_function,i=IntSlider(min=1, max=7, step=1));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "9b6cddeeb7c5451d9fe14a0dbddeb62b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(FloatSlider(value=1.0, description='i', max=6.0, min=1.0, step=1.0), Button(description=…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "interactive(slow_function, {'manual': True}, i=widgets.FloatSlider(min=1, max=6, step=1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "interact 和 interactive区别, 前者直接显示, 后者需要赋予对象, 然后执行对象(manual:True除外)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "00b078d62b6f482cb9bfb9e5e9a63451",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(FloatSlider(value=1.0, continuous_update=False, description='i', max=7.0, min=1.0, step=…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "6fe0341ff18646fe9a28e9aada1b32f5",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(IntSlider(value=1, continuous_update=False, description='i', max=7, min=1), Output()), _…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 很有用, 延迟更新\n",
    "interact(slow_function,i=FloatSlider(min=1.0, max=7.0, step=1.0, continuous_update=False));\n",
    "interact(slow_function,i=IntSlider(min=1, max=7, step=1, continuous_update=False));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "c258151d9bc440b3ba59b76122f5a7b5",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(FloatSlider(value=0.0, description='x', max=10.0, step=0.05), FloatSlider(value=5.0, des…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x_widget = FloatSlider(min=0.0, max=10.0, step=0.05)\n",
    "y_widget = FloatSlider(min=0.5, max=10.0, step=0.05, value=5.0)\n",
    "\n",
    "def update_x_range(*args):\n",
    "    x_widget.max = 2.0 * y_widget.value\n",
    "y_widget.observe(update_x_range, 'value')\n",
    "\n",
    "interact(lambda x, y: print(x, y) ,x=x_widget, y=y_widget);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Widget List\n",
    "\n",
    "[example](https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "9b26009f10744cf48b2a8a273dfeae34",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=7, continuous_update=False, description='Test:', max=10)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.IntSlider(\n",
    "    value=7,\n",
    "    min=0,\n",
    "    max=10,\n",
    "    step=1,\n",
    "    description='Test:',\n",
    "    disabled=False,\n",
    "    continuous_update=False,\n",
    "    orientation='horizontal',\n",
    "    readout=True,\n",
    "    readout_format='d'\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "fd399f5851e24abf881d7d6cf220ee1a",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "FloatSlider(value=7.5, continuous_update=False, description='Test:', max=10.0, readout_format='.1f')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.FloatSlider(\n",
    "    value=7.5,\n",
    "    min=0,\n",
    "    max=10.0,\n",
    "    step=0.1,\n",
    "    description='Test:',\n",
    "    disabled=False,\n",
    "    continuous_update=False,\n",
    "    orientation='horizontal',\n",
    "    readout=True,\n",
    "    readout_format='.1f',\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "3542dd931ae64ae2ae544087e0d191b4",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntText(value=7, description='12345678912345', layout=Layout(border='solid', width='200px'), style=Description…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.IntText(\n",
    "    value=7,\n",
    "    description='12345678912345',\n",
    "    disabled=False,\n",
    "    layout= Layout(width='200px', border='solid'),\n",
    "    style = {'description_width': '150px'},\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4d320508774e4e67a08f76c23e8be0dc",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "ToggleButton(value=False, description='Click me', icon='check', tooltip='Description')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.ToggleButton(\n",
    "    value=False,\n",
    "    description='Click me',\n",
    "    disabled=False,\n",
    "    button_style='', # 'success', 'info', 'warning', 'danger' or ''\n",
    "    tooltip='Description',\n",
    "    icon='check'\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f2302a3afad640968f19c6a76fac9453",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Checkbox(value=False, description='Check me')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.Checkbox(\n",
    "    value=False,\n",
    "    description='Check me',\n",
    "    disabled=False\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "552e10b4aaf645afa07b6cab42dac7b2",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Dropdown(description='Number:', index=1, options=('1', '2', '3'), value='2')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.Dropdown(\n",
    "    options=['1', '2', '3'],\n",
    "    value='2',\n",
    "    description='Number:',\n",
    "    disabled=False,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "c07014276cc84c5193c791a5c857d1e7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Dropdown(description='Number:', index=1, options=(('One', 1), ('Two', 2), ('Three', 3)), value=2)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.Dropdown(\n",
    "    options=[('One', 1), ('Two', 2), ('Three', 3)],\n",
    "    value=2,\n",
    "    description='Number:',\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "d3678e315b5d45a6a8023f572b4372b1",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "RadioButtons(description='Pizza topping:', options=('pepperoni', 'pineapple', 'anchovies'), value='pepperoni')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.RadioButtons(\n",
    "    options=['pepperoni', 'pineapple', 'anchovies'],\n",
    "#     value='pineapple',\n",
    "    description='Pizza topping:',\n",
    "    disabled=False\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "9064bbbc7a6e42db86e2725c36149daf",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Select(description='OS:', index=2, options=('Linux', 'Windows', 'OSX'), rows=1, value='OSX')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.Select(\n",
    "    options=['Linux', 'Windows', 'OSX'],\n",
    "    value='OSX',\n",
    "    rows=1,\n",
    "    description='OS:',\n",
    "    disabled=False\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e4ad364cac65497a9e9eea9c9d43cfa7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "SelectMultiple(description='Fruits', index=(1,), options=('Apples', 'Oranges', 'Pears'), rows=3, value=('Orang…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.SelectMultiple(\n",
    "    options=['Apples', 'Oranges', 'Pears'],\n",
    "    value=['Oranges'],\n",
    "    rows=3,\n",
    "    description='Fruits',\n",
    "    disabled=False\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f510425a3dba4c8bb0f94a80e2bd52f1",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Text(value='Hello World', description='String:', placeholder='Type something')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.Text(\n",
    "    value='Hello World',\n",
    "    placeholder='Type something',\n",
    "    description='String:',\n",
    "    disabled=False\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e6fa3cded8c3497f8446adce78263765",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(Label(value='The $m$ in $E=mc^2$:'), FloatSlider(value=0.0)))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.HBox([widgets.Label(value=\"The $m$ in $E=mc^2$:\"), widgets.FloatSlider()])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "672bfb2bd1fe4673a22309643917dbd2",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HTML(value='Hello <b>World</b>', description='Some HTML', placeholder='Some HTML')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.HTML(\n",
    "    value=\"Hello <b>World</b>\",\n",
    "    placeholder='Some HTML',\n",
    "    description='Some HTML',\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "a2f93a55a6f14424a90ed404c86ea2ed",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Button(description='Click me', icon='check', style=ButtonStyle(), tooltip='Click me')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "widgets.Button(\n",
    "    description='Click me',\n",
    "    disabled=False,\n",
    "    button_style='', # 'success', 'info', 'warning', 'danger' or ''\n",
    "    tooltip='Click me',\n",
    "    icon='check'\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "c67d94137f334f1ea02eba4fa3f50e0c",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Output(layout=Layout(border='1px solid black'))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "out = widgets.Output(layout={'border': '1px solid black'})\n",
    "out"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "with out:\n",
    "    for i in range(3):\n",
    "        print(i, 'Hello world!')\n",
    "out.clear_output()\n",
    "with out:\n",
    "    for i in range(3):\n",
    "        print(i, 'Hello world!')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "5d5ce2e93f434040b297523ce2b0ac2b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Accordion(children=(IntSlider(value=0), Text(value='')), _titles={'0': 'Slider', '1': 'Text'})"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "accordion = widgets.Accordion(children=[widgets.IntSlider(), widgets.Text()])\n",
    "accordion.set_title(0, 'Slider')\n",
    "accordion.set_title(1, 'Text')\n",
    "accordion"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "db24f73be2f745298aa3fbe8ab85ebe3",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Tab(children=(Text(value='', description='P0'), Text(value='', description='P1'), Text(value='', description='…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "tab_contents = ['P0', 'P1', 'P2', 'P3', 'P4']\n",
    "children = [widgets.Text(description=name) for name in tab_contents]\n",
    "tab = widgets.Tab()\n",
    "tab.children = children\n",
    "for i in range(len(children)):\n",
    "    tab.set_title(i, str(i))\n",
    "tab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e5d643b39b804a4cac7f7c0d43ba8422",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Tab(children=(Accordion(children=(IntSlider(value=0), Text(value='')), _titles={'0': 'Slider', '1': 'Text'}), …"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "tab_nest = widgets.Tab()\n",
    "tab_nest.children = [accordion, accordion]\n",
    "tab_nest.set_title(0, 'An accordion')\n",
    "tab_nest.set_title(1, 'Copy of the accordion')\n",
    "tab_nest"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Widget Event\n",
    "\n",
    "[example](https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Events.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Register a callback to execute when the button is clicked.\n",
      "\n",
      "        The callback will be called with one argument, the clicked button\n",
      "        widget instance.\n",
      "\n",
      "        Parameters\n",
      "        ----------\n",
      "        remove: bool (optional)\n",
      "            Set to true to remove the callback from the list of callbacks.\n",
      "        \n"
     ]
    }
   ],
   "source": [
    "print(widgets.Button.on_click.__doc__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "7e6403f463db4cc4909ff1dac51f2c33",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Button(description='Click Me!', style=ButtonStyle())"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "01e862d8e20a4ce9b0589869a1ec707f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Output()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display\n",
    "button = widgets.Button(description=\"Click Me!\")\n",
    "output = widgets.Output()\n",
    "\n",
    "display(button, output)\n",
    "\n",
    "def on_button_clicked(b):\n",
    "    with output:\n",
    "        print(\"Button clicked.\")\n",
    "\n",
    "button.on_click(on_button_clicked)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Setup a handler to be called when a trait changes.\n",
      "\n",
      "        This is used to setup dynamic notifications of trait changes.\n",
      "\n",
      "        Parameters\n",
      "        ----------\n",
      "        handler : callable\n",
      "            A callable that is called when a trait changes. Its\n",
      "            signature should be ``handler(change)``, where ``change`` is a\n",
      "            dictionary. The change dictionary at least holds a 'type' key.\n",
      "            * ``type``: the type of notification.\n",
      "            Other keys may be passed depending on the value of 'type'. In the\n",
      "            case where type is 'change', we also have the following keys:\n",
      "            * ``owner`` : the HasTraits instance\n",
      "            * ``old`` : the old value of the modified trait attribute\n",
      "            * ``new`` : the new value of the modified trait attribute\n",
      "            * ``name`` : the name of the modified trait attribute.\n",
      "        names : list, str, All\n",
      "            If names is All, the handler will apply to all traits.  If a list\n",
      "            of str, handler will apply to all names in the list.  If a\n",
      "            str, the handler will apply just to that name.\n",
      "        type : str, All (default: 'change')\n",
      "            The type of notification to filter by. If equal to All, then all\n",
      "            notifications are passed to the observe handler.\n",
      "        \n"
     ]
    }
   ],
   "source": [
    "print(widgets.Widget.observe.__doc__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "0e31a797cf7641baa582829a7eef97c7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "1683cf305fe84d92b34d1fae386a4c35",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Output()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "int_range = widgets.IntSlider()\n",
    "output2 = widgets.Output()\n",
    "\n",
    "display(int_range, output2)\n",
    "\n",
    "import pprint\n",
    "def on_value_change(change):\n",
    "    with output2:\n",
    "        pprint.pprint(change)\n",
    "\n",
    "int_range.observe(on_value_change, names='value')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "6c365df95f214f59821df0a8348c2f3a",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Label(value='The values of slider1 and slider2 are synchronized')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "d490859d76164fbba97d3869ff60ae4d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0, description='Slider 1')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "7f51305125504b1bac57ccce9ebeacd2",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0, description='Slider 2')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "caption = widgets.Label(value='The values of slider1 and slider2 are synchronized')\n",
    "sliders1, slider2 = widgets.IntSlider(description='Slider 1'),\\\n",
    "                    widgets.IntSlider(description='Slider 2')\n",
    "l = widgets.link((sliders1, 'value'), (slider2, 'value'))\n",
    "display(caption, sliders1, slider2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "6f71f3a553684caf9e8afbeadd66ed92",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Label(value='Changes in source values are reflected in target1')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "1545c285a5874efd88002667febd28ff",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0, description='Source')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "ee91f11418d646a784ebea75933713ee",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0, description='Target 1')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "caption = widgets.Label(value='Changes in source values are reflected in target1')\n",
    "source, target1 = widgets.IntSlider(description='Source'),\\\n",
    "                  widgets.IntSlider(description='Target 1')\n",
    "dl = widgets.dlink((source, 'value'), (target1, 'value'))\n",
    "display(caption, source, target1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "l.unlink()\n",
    "dl.unlink()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "9537a7273be14f9ca2c9a9e2485d75f5",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Label(value='The values of range1 and range2 are synchronized')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "807d2b958b35464d8bcd23644bb1ad73",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0, description='Range 1')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "43c4231dda174f7eaafeebc422e723f1",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0, description='Range 2')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "caption = widgets.Label(value='The values of range1 and range2 are synchronized')\n",
    "range1, range2 = widgets.IntSlider(description='Range 1'),\\\n",
    "                 widgets.IntSlider(description='Range 2')\n",
    "l = widgets.jslink((range1, 'value'), (range2, 'value'))\n",
    "display(caption, range1, range2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "07e080424ab5429ab8566e2be105ced3",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "VBox(children=(IntSlider(value=0, continuous_update=False, description='Delayed'), IntText(value=0, descriptio…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "a = widgets.IntSlider(description=\"Delayed\", continuous_update=False)\n",
    "b = widgets.IntText(description=\"Delayed\", continuous_update=False)\n",
    "c = widgets.IntSlider(description=\"Continuous\", continuous_update=True)\n",
    "d = widgets.IntText(description=\"Continuous\", continuous_update=True)\n",
    "\n",
    "widgets.link((a, 'value'), (b, 'value'))\n",
    "widgets.link((a, 'value'), (c, 'value'))\n",
    "widgets.link((a, 'value'), (d, 'value'))\n",
    "widgets.VBox([a,b,c,d])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "a.value = 100"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "d68879eafc6448c1887916e74fe44eda",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Button(description='Click Me!', style=ButtonStyle())"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "6d6be5d91d954d64814b5c9d445dd85c",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Output()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display\n",
    "button = widgets.Button(description=\"Click Me!\")\n",
    "output = widgets.Output()\n",
    "\n",
    "display(button, output)\n",
    "\n",
    "def on_button_clicked(b):\n",
    "    with output:\n",
    "        print(\"Button clicked.\")\n",
    "\n",
    "button.on_click(on_button_clicked)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "7bb1e6f97b694f7ba1cd0c6c3f1394d4",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "VBox(children=(Play(value=1, interval=2000, min=1), IntSlider(value=1, min=1), Output()))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import ipywidgets as widgets\n",
    "\n",
    "out = widgets.Output()\n",
    "def on_value_change(change):\n",
    "    with out:\n",
    "        clear_output()\n",
    "        print(type(change['owner']))\n",
    "        print(change['new'])\n",
    "\n",
    "slider = widgets.IntSlider(min=1, max=100, step=1, continuous_update=True)\n",
    "play = widgets.Play(min=1, interval=2000)\n",
    "\n",
    "slider.observe(on_value_change, 'value')\n",
    "widgets.jslink((play, 'value'), (slider, 'value'))\n",
    "widgets.VBox([play, slider, out])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "915b868c8ddf466492555e20bcf51443",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from ipywidgets import *\n",
    "from IPython.display import display, HTML\n",
    "w = IntSlider()\n",
    "display(w)\n",
    "\n",
    "# 不需要display(w, out), 对比上面的\n",
    "def callback(change):\n",
    "    display(HTML('<h3>Arbitrary HTML</h3>'))\n",
    "\n",
    "w.observe(callback, names=['value'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  Custom Widget"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "from traitlets import Unicode, Bool, validate, TraitError\n",
    "from ipywidgets import DOMWidget, register"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "@register\n",
    "class Email(DOMWidget):\n",
    "    _view_name = Unicode('EmailView').tag(sync=True)\n",
    "    _view_module = Unicode('email_widget').tag(sync=True)\n",
    "    _view_module_version = Unicode('0.1.0').tag(sync=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "require.undef('email_widget');\n",
       "\n",
       "define('email_widget', [\"@jupyter-widgets/base\"], function(widgets) {\n",
       "\n",
       "    var EmailView = widgets.DOMWidgetView.extend({\n",
       "\n",
       "        // Render the view.\n",
       "        render: function() {\n",
       "            this.email_input = document.createElement('input');\n",
       "            this.email_input.type = 'email';\n",
       "            this.email_input.value = 'example@example.com';\n",
       "            this.email_input.disabled = true;\n",
       "\n",
       "            this.el.appendChild(this.email_input);\n",
       "        },\n",
       "    });\n",
       "\n",
       "    return {\n",
       "        EmailView: EmailView\n",
       "    };\n",
       "});\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%javascript\n",
    "require.undef('email_widget');\n",
    "\n",
    "define('email_widget', [\"@jupyter-widgets/base\"], function(widgets) {\n",
    "\n",
    "    var EmailView = widgets.DOMWidgetView.extend({\n",
    "\n",
    "        // Render the view.\n",
    "        render: function() {\n",
    "            this.email_input = document.createElement('input');\n",
    "            this.email_input.type = 'email';\n",
    "            this.email_input.value = 'example@example.com';\n",
    "            this.email_input.disabled = true;\n",
    "\n",
    "            this.el.appendChild(this.email_input);\n",
    "        },\n",
    "    });\n",
    "\n",
    "    return {\n",
    "        EmailView: EmailView\n",
    "    };\n",
    "});"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "2d1c8b5c44f448209b87d13fed2f04c9",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Email()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "Email()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "@register\n",
    "class Email(DOMWidget):\n",
    "    _view_name = Unicode('EmailView').tag(sync=True)\n",
    "    _view_module = Unicode('email_widget').tag(sync=True)\n",
    "    _view_module_version = Unicode('0.1.0').tag(sync=True)\n",
    "\n",
    "    # Attributes\n",
    "    value = Unicode('example@example.com', help=\"The email value.\").tag(sync=True)\n",
    "    disabled = Bool(False, help=\"Enable or disable user changes.\").tag(sync=True)\n",
    "\n",
    "    # Basic validator for the email value\n",
    "    @validate('value')\n",
    "    def _valid_value(self, proposal):\n",
    "        if proposal['value'].count(\"@\") != 1:\n",
    "            raise TraitError('Invalid email value: it must contain an \"@\" character')\n",
    "        if proposal['value'].count(\".\") == 0:\n",
    "            raise TraitError('Invalid email value: it must contain at least one \".\" character')\n",
    "        return proposal['value']\n",
    "\n",
    "  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "require.undef('email_widget');\n",
       "\n",
       "define('email_widget', [\"@jupyter-widgets/base\"], function(widgets) {\n",
       "\n",
       "    var EmailView = widgets.DOMWidgetView.extend({\n",
       "\n",
       "        // Render the view.\n",
       "        render: function() {\n",
       "            this.email_input = document.createElement('input');\n",
       "            this.email_input.type = 'email';\n",
       "            this.email_input.value = this.model.get('value');\n",
       "            this.email_input.disabled = this.model.get('disabled');\n",
       "\n",
       "            this.el.appendChild(this.email_input);\n",
       "        },\n",
       "    });\n",
       "\n",
       "    return {\n",
       "        EmailView: EmailView\n",
       "    };\n",
       "});\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%javascript\n",
    "require.undef('email_widget');\n",
    "\n",
    "define('email_widget', [\"@jupyter-widgets/base\"], function(widgets) {\n",
    "\n",
    "    var EmailView = widgets.DOMWidgetView.extend({\n",
    "\n",
    "        // Render the view.\n",
    "        render: function() {\n",
    "            this.email_input = document.createElement('input');\n",
    "            this.email_input.type = 'email';\n",
    "            this.email_input.value = this.model.get('value');\n",
    "            this.email_input.disabled = this.model.get('disabled');\n",
    "\n",
    "            this.el.appendChild(this.email_input);\n",
    "        },\n",
    "    });\n",
    "\n",
    "    return {\n",
    "        EmailView: EmailView\n",
    "    };\n",
    "});"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "3094aad4dab14dbdbbe03bd685c81655",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Email(disabled=True, value='john.doe@domain.com')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "Email(value='john.doe@domain.com', disabled=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "require.undef('email_widget');\n",
       "\n",
       "define('email_widget', [\"@jupyter-widgets/base\"], function(widgets) {\n",
       "\n",
       "    var EmailView = widgets.DOMWidgetView.extend({\n",
       "\n",
       "        // Render the view.\n",
       "        render: function() {\n",
       "            this.email_input = document.createElement('input');\n",
       "            this.email_input.type = 'email';\n",
       "            this.email_input.value = this.model.get('value');\n",
       "            this.email_input.disabled = this.model.get('disabled');\n",
       "\n",
       "            this.el.appendChild(this.email_input);\n",
       "\n",
       "            // Python -> JavaScript update\n",
       "            this.model.on('change:value', this.value_changed, this);\n",
       "            this.model.on('change:disabled', this.disabled_changed, this);\n",
       "\n",
       "            // JavaScript -> Python update\n",
       "            this.email_input.onchange = this.input_changed.bind(this);\n",
       "        },\n",
       "\n",
       "        value_changed: function() {\n",
       "            this.email_input.value = this.model.get('value');\n",
       "        },\n",
       "\n",
       "        disabled_changed: function() {\n",
       "            this.email_input.disabled = this.model.get('disabled');\n",
       "        },\n",
       "\n",
       "        input_changed: function() {\n",
       "            this.model.set('value', this.email_input.value);\n",
       "            this.model.save_changes();\n",
       "        },\n",
       "    });\n",
       "\n",
       "    return {\n",
       "        EmailView: EmailView\n",
       "    };\n",
       "});\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%javascript\n",
    "require.undef('email_widget');\n",
    "\n",
    "define('email_widget', [\"@jupyter-widgets/base\"], function(widgets) {\n",
    "\n",
    "    var EmailView = widgets.DOMWidgetView.extend({\n",
    "\n",
    "        // Render the view.\n",
    "        render: function() {\n",
    "            this.email_input = document.createElement('input');\n",
    "            this.email_input.type = 'email';\n",
    "            this.email_input.value = this.model.get('value');\n",
    "            this.email_input.disabled = this.model.get('disabled');\n",
    "\n",
    "            this.el.appendChild(this.email_input);\n",
    "\n",
    "            // Python -> JavaScript update\n",
    "            this.model.on('change:value', this.value_changed, this);\n",
    "            this.model.on('change:disabled', this.disabled_changed, this);\n",
    "\n",
    "            // JavaScript -> Python update\n",
    "            this.email_input.onchange = this.input_changed.bind(this);\n",
    "        },\n",
    "\n",
    "        value_changed: function() {\n",
    "            this.email_input.value = this.model.get('value');\n",
    "        },\n",
    "\n",
    "        disabled_changed: function() {\n",
    "            this.email_input.disabled = this.model.get('disabled');\n",
    "        },\n",
    "\n",
    "        input_changed: function() {\n",
    "            this.model.set('value', this.email_input.value);\n",
    "            this.model.save_changes();\n",
    "        },\n",
    "    });\n",
    "\n",
    "    return {\n",
    "        EmailView: EmailView\n",
    "    };\n",
    "});"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "1bbdd2aa29db4729b75a9d9913a5e088",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Email(value='john.doe@domain.com')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "email = Email(value='john.doe@domain.com', disabled=False)\n",
    "email"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'john.doe@domain.com'"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "email.value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [],
   "source": [
    "email.value = 'jane.doe@domain.com'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "1bbdd2aa29db4729b75a9d9913a5e088",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Email(value='jane.doe@domain.com')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "email"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Layout"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f9eb085539c2465481ec6bb85652e2c2",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Box(children=(Button(button_style='danger', description='correct', style=ButtonStyle()), Button(button_style='…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "words = ['correct', 'horse', 'battery', 'staple']\n",
    "items = [Button(description=word, button_style='danger') for word in words]\n",
    "box = Box(children=items)\n",
    "box"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "46c0fab1a47247bba80ed0b16a3978f9",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Box(children=(Button(button_style='danger', description='correct', layout=Layout(width='auto'), style=ButtonSt…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "items_layout = Layout( width='auto')     # override the default width of the button to 'auto' to let the button grow\n",
    "\n",
    "box_layout = Layout(display='flex',\n",
    "                    flex_flow='column', # 'row'\n",
    "                    align_items='stretch',\n",
    "                    border='solid',\n",
    "                    width='50%')\n",
    "\n",
    "words = ['correct', 'horse', 'battery', 'staple']\n",
    "items = [Button(description=word, layout=items_layout, button_style='danger') for word in words]\n",
    "box = Box(children=items, layout=box_layout)\n",
    "box"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "8fe4cbfbc21b41b0a1602e711e177d1b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "VBox(children=(Box(children=(Button(button_style='danger', description='weight=1; auto', layout=Layout(flex='1…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Items flex proportionally to the weight and the left over space around the text\n",
    "items_auto = [\n",
    "    Button(description='weight=1; auto', layout=Layout(flex='1 1 auto', width='auto'), button_style='danger'),\n",
    "    Button(description='weight=3; auto', layout=Layout(flex='3 1 auto', width='auto'), button_style='danger'),\n",
    "    Button(description='weight=1; auto', layout=Layout(flex='1 1 auto', width='auto'), button_style='danger'),\n",
    " ]\n",
    "\n",
    "# Items flex proportionally to the weight\n",
    "items_0 = [\n",
    "    Button(description='weight=1; 0%', layout=Layout(flex='1 1 0%', width='auto'), button_style='danger'),\n",
    "    Button(description='weight=3; 0%', layout=Layout(flex='3 1 0%', width='auto'), button_style='danger'),\n",
    "    Button(description='weight=1; 0%', layout=Layout(flex='1 1 0%', width='auto'), button_style='danger'),\n",
    " ]\n",
    "box_layout = Layout(display='flex',\n",
    "                    flex_flow='row',\n",
    "                    align_items='stretch',\n",
    "                    width='70%')\n",
    "box_auto = Box(children=items_auto, layout=box_layout)\n",
    "box_0 = Box(children=items_0, layout=box_layout)\n",
    "VBox([box_auto, box_0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "bf83aed8de694bcd893baf3a5107fa40",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Box(children=(Box(children=(Label(value='Age of the captain'), IntSlider(value=40, max=60, min=40)), layout=La…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from ipywidgets import Layout, Button, Box, FloatText, Textarea, Dropdown, Label, IntSlider\n",
    "\n",
    "form_item_layout = Layout(\n",
    "    display='flex',\n",
    "    flex_flow='row',\n",
    "    justify_content='space-between'\n",
    ")\n",
    "\n",
    "form_items = [\n",
    "    Box([Label(value='Age of the captain'), IntSlider(min=40, max=60)], layout=form_item_layout),\n",
    "    Box([Label(value='Egg style'),\n",
    "         Dropdown(options=['Scrambled', 'Sunny side up', 'Over easy'])], layout=form_item_layout),\n",
    "    Box([Label(value='Ship size'),\n",
    "         FloatText()], layout=form_item_layout),\n",
    "    Box([Label(value='Information'),\n",
    "         Textarea()], layout=form_item_layout)\n",
    "]\n",
    "\n",
    "form = Box(form_items, layout=Layout(\n",
    "    display='flex',\n",
    "    flex_flow='column',\n",
    "    border='solid 2px',\n",
    "    align_items='stretch',\n",
    "    width='50%'\n",
    "))\n",
    "form"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f7158fc898ee4df08ff5d6f8b912cc4a",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "VBox(children=(Label(value='Scroll horizontally:'), Box(children=(Button(button_style='warning', description='…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from ipywidgets import Layout, Button, VBox, Label\n",
    "\n",
    "item_layout = Layout(height='100px', min_width='40px')\n",
    "items = [Button(layout=item_layout, description=str(i), button_style='warning') for i in range(40)]\n",
    "box_layout = Layout(overflow='scroll',\n",
    "                    border='3px solid black',\n",
    "                    width='500px',\n",
    "                    height='',\n",
    "                    flex_flow='row',\n",
    "                    display='flex')\n",
    "carousel = Box(children=items, layout=box_layout)\n",
    "VBox([Label('Scroll horizontally:'), carousel])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "ca604fa18a77411e9d3a56c850f147e6",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Button(description='Custom color', style=ButtonStyle(button_color='lightgreen'))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "b1 = Button(description='Custom color')\n",
    "b1.style.button_color = 'lightgreen'\n",
    "b1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['_model_module',\n",
       " '_model_module_version',\n",
       " '_model_name',\n",
       " '_view_count',\n",
       " '_view_module',\n",
       " '_view_module_version',\n",
       " '_view_name',\n",
       " 'button_color',\n",
       " 'font_weight']"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b1.style.keys"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipywidgets import Button, GridBox, Layout, ButtonStyle"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "82380707e190421f8a711be5c80171fd",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "GridBox(children=(Button(description='Header', layout=Layout(grid_area='header', width='auto'), style=ButtonSt…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "header  = Button(description='Header',\n",
    "                 layout=Layout(width='auto', grid_area='header'),\n",
    "                 style=ButtonStyle(button_color='lightblue'))\n",
    "main    = Button(description='Main',\n",
    "                 layout=Layout(width='auto', grid_area='main'),\n",
    "                 style=ButtonStyle(button_color='moccasin'))\n",
    "sidebar = Button(description='Sidebar',\n",
    "                 layout=Layout(width='auto', grid_area='sidebar'),\n",
    "                 style=ButtonStyle(button_color='salmon'))\n",
    "footer  = Button(description='Footer',\n",
    "                 layout=Layout(width='auto', grid_area='footer'),\n",
    "                 style=ButtonStyle(button_color='olive'))\n",
    "\n",
    "GridBox(children=[header, main, sidebar, footer],\n",
    "        layout=Layout(\n",
    "            width='50%',\n",
    "            grid_template_rows='auto auto auto',\n",
    "            grid_template_columns='25% 25% 25% 25%',\n",
    "            grid_template_areas='''\n",
    "            \"header header header header\"\n",
    "            \"main main . sidebar \"\n",
    "            \"footer footer footer footer\"\n",
    "            ''')\n",
    "       )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "ac18444edd334e7da9624af3798db98f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "GridBox(children=(Button(layout=Layout(height='auto', width='auto'), style=ButtonStyle(button_color='darkseagr…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "GridBox(children=[Button(layout=Layout(width='auto', height='auto'),\n",
    "                     style=ButtonStyle(button_color='darkseagreen')) for i in range(9)\n",
    "             ],\n",
    "    layout=Layout(\n",
    "        width='50%',\n",
    "        grid_template_columns='100px 50px 100px',\n",
    "        grid_template_rows='80px auto 80px',\n",
    "        grid_gap='5px 10px')\n",
    "   )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "8f9e5f171ce44704be8556d2273d4b8d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "GridBox(children=(Button(layout=Layout(height='auto', width='auto'), style=ButtonStyle(button_color='darkseagr…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "gb = GridBox(children=[Button(layout=Layout(width='auto', height='auto'),\n",
    "                     style=ButtonStyle(button_color='darkseagreen')) for i in range(12)\n",
    "             ],\n",
    "    layout=Layout(\n",
    "        width='50%',\n",
    "        grid_template_columns='25% 25% 25%',\n",
    "        # grid_template_rows='80px auto 80px',\n",
    "        grid_gap='5px 10px')\n",
    "   )\n",
    "gb.layout.grid_template_rows = '80px auto auto 80px'\n",
    "gb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "139799007994936 139799007994656 139799007994656\n"
     ]
    }
   ],
   "source": [
    "lo = Layout(display='flex',\n",
    "                flex_flow='row wrap', # 自动换行\n",
    "                align_items='stretch',\n",
    "                justify_content='flex-start',\n",
    "                border='solid', width='100%')\n",
    "btns = [Button(description='btn-%d' % i) for i in range(12)]\n",
    "hbox1 = HBox(btns[:10], layout=lo)\n",
    "ddns = [Dropdown(description='dd-%d' % i) for i in range(5)]\n",
    "chgbox = VBox(btns[5:8])\n",
    "ddns[0].trigger_box = chgbox\n",
    "print(id(ddns[0]), id(ddns[0].trigger_box), id(chgbox))\n",
    "vboxes = [VBox([ddns[0]] + [chgbox], layout=Layout(align_items='center')) for i in range(5)]\n",
    "hbox2 = HBox(vboxes, layout=lo)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f023484835b44395a6dd511576b6eb3b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "VBox(children=(HBox(children=(Button(description='btn-0', style=ButtonStyle()), Button(description='btn-1', st…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "BB = VBox([hbox1] + [hbox2])\n",
    "BB"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "139799007994936 139799007994656\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f023484835b44395a6dd511576b6eb3b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "VBox(children=(HBox(children=(Button(description='btn-0', style=ButtonStyle()), Button(description='btn-1', st…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 可以实现更新, 当dropdown修改时, 更新相关的vbox\n",
    "# chgbox.children = btns[8:12]\n",
    "print(id(ddns[0]), id(ddns[0].trigger_box))\n",
    "ddns[0].trigger_box.children =  btns[8:12]\n",
    "BB"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Low Level"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "cb12b128e9e6431cb2492c47bdf028e7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "cb12b128e9e6431cb2492c47bdf028e7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "w = IntSlider()\n",
    "display(w, w)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "cb12b128e9e6431cb2492c47bdf028e7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e51a243530f0412d936c6be992ea5124",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "FloatSlider(value=0.0)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "slider = widgets.FloatSlider()\n",
    "display(slider)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ASync"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "915d0e558a90494d8f257dce68692aaa",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "FloatProgress(value=0.0, max=1.0)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import threading\n",
    "from IPython.display import display\n",
    "import ipywidgets as widgets\n",
    "import time\n",
    "progress = widgets.FloatProgress(value=0.0, min=0.0, max=1.0)\n",
    "\n",
    "def work(progress):\n",
    "    total = 10\n",
    "    for i in range(total):\n",
    "        time.sleep(0.2)\n",
    "        progress.value = float(i+1)/total\n",
    "\n",
    "thread = threading.Thread(target=work, args=(progress,))\n",
    "display(progress)\n",
    "thread.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Other"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [],
   "source": [
    "N_samples = 25\n",
    "x_min = -5\n",
    "x_max = 5\n",
    "x1= np.linspace(x_min,x_max,N_samples*5)\n",
    "x= np.random.choice(x1,size=N_samples)\n",
    "noise_std=1\n",
    "noise_mean=0\n",
    "noise_magnitude = 2\n",
    "\n",
    "def func_gen(N_samples,x_min,x_max,noise_magnitude,noise_sd,noise_mean):\n",
    "    x1= np.linspace(x_min,x_max,N_samples*5)\n",
    "    x= np.random.choice(x1,size=N_samples)\n",
    "    y=2*x-0.6*x**2+0.2*x**3+18*np.sin(x)\n",
    "    y1=2*x1-0.6*x1**2+0.2*x1**3+18*np.sin(x1)\n",
    "    y= y+noise_magnitude*np.random.normal(loc=noise_mean,scale=noise_sd,size=N_samples)\n",
    "    plt.figure(figsize=(8,5))\n",
    "    plt.plot(x1,y1,c='k',lw=2)\n",
    "    plt.scatter(x,y,edgecolors='k',c='yellow',s=60)\n",
    "    plt.grid(True)\n",
    "    plt.show()\n",
    "    return (x,y,x1,y1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "277f9bfecac840b593fdece8b1ecfaa2",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(Dropdown(description='N_samples', options={'Low (50 samples)': 50, 'High (200 samples)':…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "p = interactive(func_gen,N_samples={'Low (50 samples)':50,'High (200 samples)':200},x_min=(-5,0,1), x_max=(0,5,1),\n",
    "              noise_magnitude=(0,5,1),noise_sd=(0.1,1,0.1),noise_mean=(-2,2,0.5))\n",
    "display(p)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import IFrame, HTML, Javascript, display, Markdown, clear_output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# IFrame('http://www.baidu.com', width=850, height=650)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<input type=\"file\" accept=\".dat\" id=\"files\" name=\"files[]\" multiple />\n",
       "<output id=\"list\"></output>\n",
       "\n",
       "<script>\n",
       "    function handleFileSelect(evt) {\n",
       "        var files = evt.target.files;\n",
       "        var output = [];\n",
       "        IPython.notebook.kernel.execute(\"lstFiles=[]\");\n",
       "        for (var i = 0, f; f = files[i]; i++) {\n",
       "            IPython.notebook.kernel.execute(\"lstFiles.append('\" + f.name + \"')\");\n",
       "            output.push('<li><strong>', f.name, '</strong></li>');\n",
       "        }\n",
       "        document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';\n",
       "    }\n",
       "\n",
       "    document.getElementById('files').addEventListener('change', handleFileSelect, false);\n",
       "</script>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%html\n",
    "\n",
    "<input type=\"file\" accept=\".dat\" id=\"files\" name=\"files[]\" multiple />\n",
    "<output id=\"list\"></output>\n",
    "\n",
    "<script>\n",
    "    function handleFileSelect(evt) {\n",
    "        var files = evt.target.files;\n",
    "        var output = [];\n",
    "        IPython.notebook.kernel.execute(\"lstFiles=[]\");\n",
    "        for (var i = 0, f; f = files[i]; i++) {\n",
    "            IPython.notebook.kernel.execute(\"lstFiles.append('\" + f.name + \"')\");\n",
    "            output.push('<li><strong>', f.name, '</strong></li>');\n",
    "        }\n",
    "        document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';\n",
    "    }\n",
    "\n",
    "    document.getElementById('files').addEventListener('change', handleFileSelect, false);\n",
    "</script>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [],
   "source": [
    "text = widgets.Text(\n",
    "       value='My Text',\n",
    "       description='Title', )\n",
    "\n",
    "calendar = widgets.DatePicker(\n",
    "           description='Select Date')\n",
    "\n",
    "slider = widgets.FloatSlider(\n",
    "         value=1,\n",
    "         min=0,\n",
    "         max=10.0,\n",
    "         step=0.1,)\n",
    "\n",
    "menu = widgets.Dropdown(\n",
    "       options=['red', 'blue', 'green'],\n",
    "       value='red',\n",
    "       description='Color:')\n",
    "\n",
    "checkbox = widgets.Checkbox(\n",
    "           description='Check to invert',)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "adeb194fa01f472e8d7894da6ff3d7bf",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Dropdown(description='Color:', options=('red', 'blue', 'green'), value='red')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "menu"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4b84b445e29c416ea4677e644e1b9451",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "VBox(children=(Text(value='My Text', description='Title'), FloatSlider(value=1.0, max=10.0), Dropdown(descript…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "box = widgets.VBox([text, slider, menu, calendar, checkbox ])\n",
    "box"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "7ae4fd2e2ddf44c5af1c9f7de005a13b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Tab(children=(VBox(children=(Text(value='My Text', description='Title'), FloatSlider(value=1.0, max=10.0), Dro…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# defining a list with the contents of our windows\n",
    "children = [box, box]# initializing a tab\n",
    "tab = widgets.Tab()\n",
    "# setting the tab windows \n",
    "tab.children = children# changing the title of the first and second window\n",
    "tab.set_title(0, 'box')\n",
    "tab.set_title(1, 'copy of box')\n",
    "\n",
    "tab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'aaa'"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "intbox = IntText(a=\"1\")\n",
    "intbox.a = 'aaa'\n",
    "intbox.a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 多个选择, 搜索"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [],
   "source": [
    "def multi_checkbox_widget(descriptions):\n",
    "    \"\"\" Widget with a search field and lots of checkboxes \"\"\"\n",
    "    search_widget = widgets.Text()\n",
    "    options_dict = {description: widgets.Checkbox(description=description, value=False) for description in descriptions}\n",
    "    options = [options_dict[description] for description in descriptions]\n",
    "    # options_widget = widgets.VBox(options, layout={'overflow': 'scroll'})\n",
    "    options_widget = widgets.VBox(options, layout=Layout(flex_flow='row wrap', width='100%'))\n",
    "    multi_select = widgets.VBox([search_widget, options_widget])\n",
    "\n",
    "    # Wire the search field to the checkboxes\n",
    "    def on_text_change(change):\n",
    "        search_input = change['new']\n",
    "        if search_input == '':\n",
    "            # Reset search field\n",
    "            new_options = [options_dict[description] for description in descriptions]\n",
    "        else:\n",
    "            # Filter by search field using difflib.\n",
    "            close_matches = difflib.get_close_matches(search_input, descriptions, cutoff=0.0)\n",
    "            new_options = [options_dict[description] for description in close_matches]\n",
    "        options_widget.children = new_options\n",
    "\n",
    "    search_widget.observe(on_text_change, names='value')\n",
    "    return multi_select"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [],
   "source": [
    "import difflib\n",
    "import random\n",
    "# import requests\n",
    "# words_url = 'https://svnweb.freebsd.org/csrg/share/dict/words?view=co&content-type=text/plain'\n",
    "# response = requests.get(words_url)\n",
    "# response.raise_for_status()\n",
    "# words = response.text\n",
    "# words = set([word.lower() for word in words.splitlines()])\n",
    "words = [\n",
    "\"blowup\",\n",
    "\"flathead\",\n",
    "\"catch\",\n",
    "\"barberry\",\n",
    "\"exercise\",\n",
    "\"hallucinogen\",\n",
    "\"sus\",\n",
    "\"polyandrous\",\n",
    "\"crowley\",\n",
    "\"fauna\"]\n",
    "mulopts = random.sample(words, 10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "eb234f375ca14b49b609ac24df473211",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "VBox(children=(Text(value=''), VBox(children=(Checkbox(value=False, description='fauna'), Checkbox(value=False…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "mul = multi_checkbox_widget(mulopts)\n",
    "mul"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "selected_options = [w.description for w in mul.children[1].children if w.value]\n",
    "selected_options "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [],
   "source": [
    "import ipywidgets\n",
    "class SearchSelectMultiple(ipywidgets.VBox):\n",
    "    def __init__(self, options, *args, **kwargs):\n",
    "        super(SearchSelectMultiple, self).__init__(*args, **kwargs)\n",
    "        self.select_multiple = ipywidgets.SelectMultiple(\n",
    "            options=sorted(options),\n",
    "            value=(),\n",
    "            disabled=False,\n",
    "            layout={'height': '200px', 'width': '300px'}\n",
    "        )\n",
    "        update = ipywidgets.Button(\n",
    "            description='Update', style={'description_width': 'initial'}, layout={'width': 'initial'})\n",
    "        self.description = kwargs.get('description') or '' # TODO move into placeholder\n",
    "        self.search_widget = ipywidgets.Text(\n",
    "            placeholder=self.description,\n",
    "            layout={'width': self.select_multiple.layout.width})\n",
    "\n",
    "        # Wire the search field to the checkboxes\n",
    "        def on_text_change(change):\n",
    "            search_input = change['new']\n",
    "            if search_input == '':\n",
    "                # Reset search field\n",
    "                new_options = sorted(options)\n",
    "            else:\n",
    "                # Filter by search field.\n",
    "                new_options = [a for a in options if search_input in a]\n",
    "            self.select_multiple.options = sorted(new_options)\n",
    "\n",
    "        self.search_widget.observe(on_text_change, names='value')\n",
    "        self.children = [self.search_widget, self.select_multiple]\n",
    "\n",
    "    @property\n",
    "    def value(self):\n",
    "        return self.select_multiple.value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "82227523880742088b4f4ef99b43b290",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "SearchSelectMultiple(children=(Text(value='', layout=Layout(width='300px'), placeholder=''), SelectMultiple(la…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "SearchSelectMultiple(options=mulopts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ParameterSelectList(ipywidgets.VBox):\n",
    "    def __init__(self, param_dict, description, *args, **kwargs):\n",
    "        super(ParameterSelectList, self).__init__(*args, **kwargs)\n",
    "        self.description = description\n",
    "        self.update_params(param_dict)\n",
    "\n",
    "    def update_params(self, param_dict):\n",
    "        children = []\n",
    "        for (k, v) in param_dict.items():\n",
    "            if isinstance(v, bool):\n",
    "                wid = ipywidgets.ToggleButton(\n",
    "                    description=k, value=v, disabled=False, button_style='',\n",
    "                    tooltip='Description', icon='check',\n",
    "                    style={'description_width': 'initial'})\n",
    "                children.append(wid)\n",
    "            elif isinstance(v, (int, np.integer)):\n",
    "                wid = ipywidgets.IntText(\n",
    "                    description=k, value=v,\n",
    "                    style={'description_width': 'initial'})\n",
    "                children.append(wid)\n",
    "            elif isinstance(v, (float, np.float)):\n",
    "                wid = ipywidgets.FloatText(\n",
    "                    description=k, value=v,\n",
    "                    style={'description_width': 'initial'})\n",
    "                children.append(wid)\n",
    "            elif not isinstance(v, dict):\n",
    "                wid = ipywidgets.Text(\n",
    "                    description=k, value=str(v),\n",
    "                    style={'description_width': 'initial'})\n",
    "                children.append(wid)\n",
    "            else:\n",
    "                print('not showing dictionary')\n",
    "        self.children = children\n",
    "\n",
    "    @property\n",
    "    def value(self):\n",
    "        keys = []\n",
    "        values = []\n",
    "        for ch in self.children:\n",
    "            keys.append(ch.description)\n",
    "            values.append(ch.value)\n",
    "        return dict(zip(keys, values))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "8c665f984d7f4b52a1a8132db63670fd",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "ParameterSelectList(children=(IntText(value=12, description='a', style=DescriptionStyle(description_width='ini…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "ParameterSelectList(param_dict={'a': 12, 'b': True, 'c': 1.0}, description='test')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
